import matplotlib.pyplot as plt
from sklearn import neighbors
from sklearn.datasets.samples_generator import make_blobs
from sklearn.cluster import AffinityPropagation
import scipy.io as scio
from sklearn.decomposition import PCA
from numpy import unique
from numpy import where
import ann as ann
import numpy as np


# import sklearn.datasets

def init_sample():
    """
    第一步：生成测试数据
        1.生成实际中心为centers的测试样本300个，
        2.Xn是包含150个(x,y)点的二维数组
        3.labels_true为其对应的真是类别标签
    """
    # 生成的测试数据的中心点
    centers = [[1, 1], [-1, -1], [1, -1]]
    # 生成数据
    X, label_true = make_blobs(n_samples=15000, centers=centers, cluster_std=0.5, random_state=0)
    # return X, label_true
    return X

def plot(class_cen, X, c_list):
    # 画图
    colors = ['red', 'blue', 'black', 'green', 'yellow']
    plt.figure(figsize=(8, 6))
    plt.xlim([-3, 3])
    plt.ylim([-3, 3])
    for i in range(len(X)):
        d1 = Xn[i]
        d2 = Xn[c_list[i]]
        c = class_cen.index(c_list[i])
        plt.plot([d2[0], d1[0]], [d2[1], d1[1]], color=colors[c], linewidth=1)
        # if i == c_list[i] :
        #    plt.scatter(d1[0],d1[1],color=colors[c],linewidth=3)
        # else :
        #    plt.scatter(d1[0],d1[1],color=colors[c],linewidth=1)
    plt.savefig('AP 聚类.png')
    plt.show()

def simi_matrix(Xn):
    simi = []
    for m in Xn:
        ##每个数字与所有数字的相似度列表，即矩阵中的一行
        temp = []
        for n in Xn:
             ##采用负的欧式距离计算相似度
            s =-np.sqrt((m[0]-n[0])**2 + (m[1]-n[1])**2 + (m[2]-n[2])**2 + (m[3]-n[3])**2 + (m[4]-n[4])**2 + (m[5]-n[5])**2)
            temp.append(s)
        simi.append(temp)
    return simi

def accuracy(prediction, labels):
    return np.mean(np.sqrt(np.sum((prediction - labels) ** 2, 1)))

def knn_reg(off_rss,off_loc,trace,rss,k):
    # uniform 本节点所有邻节点投票权重一样
    # weight 投票权重
    knn_reg = neighbors.KNeighborsRegressor(k, weights='uniform', metric='euclidean')
    # print(knn_reg)
    knn_reg.fit(off_rss, off_loc)
    predictions = knn_reg.predict(rss)
    # print(predictions)
    plt_loc_rea(predictions,trace,name='预测后的点与真实点对比'+str(k))
    acc = accuracy(predictions, trace)
    print("acc:", acc / 100, "m")
    # for i in range(len(predictions)):
    #     print(predictions[i],trace[i])
    return acc / 100
def plt_loc(data,name):
    plt.figure(figsize=(20, 15))
    plt.xticks(fontsize=24)
    plt.yticks(fontsize=24)
    plt.scatter(data[:, 0], data[:, 1])
    plt.savefig(f'ap_output/{name}')
    plt.show()
def plt_loc_rea(pre,data,name):
    plt.figure(figsize=(20, 15))
    plt.xticks(fontsize=24)
    plt.yticks(fontsize=24)
    plt.scatter(data[:, 0], data[:, 1])
    plt.scatter(pre[:, 0], pre[:, 1])
    plt.savefig(f'ap_output/{name}')
    plt.show()
def plt_ap_loc(yhat,clusters,data,name):
    plt.figure(figsize=(15, 10))
    # 为每个群集的样本创建散点图
    for cluster in clusters:
        # 获取此群集的示例的行索引
        row_ix = where(yhat == cluster)
        print(row_ix)
        # 创建这些样本的散布
        plt.scatter(data[row_ix, 0], data[row_ix, 1])
    # # 绘制散点图
    plt.xticks(fontsize=24)
    plt.yticks(fontsize=24)
    plt.savefig(f'ap_output/{name}')
    plt.show()
if __name__ == '__main__':

    offline_data = scio.loadmat('sim_data/offline_data_random.mat')
    online_data = scio.loadmat('sim_data/online_data.mat')

    # 离线数据
    offline_location = offline_data['offline_location']
    offline_rss = offline_data['offline_rss']
    offline_rss = offline_rss[:2000]
    offline_location = offline_location[:2000]

    print(offline_rss.shape)
    print(offline_location)

    # 在线数据
    trace, rss = online_data['trace'][:200], online_data['rss'][:200]
    # print('未ap聚类的值')
    sum_ap = 0
    for i in range(5,21):
        print('第',i,'次')
        sum_ap += knn_reg(offline_rss, offline_location, trace, rss,i)
    print(sum_ap / 16)
    # 离线真实位置
    plt_loc(offline_location,'离线收集实际位置')
    #  在线轨迹图
    plt_loc(trace,'在线测试实际位置')
    p = -40000

    # data = np.append(offline_rss,rss,axis=0)
    # loc = np.append(offline_location,trace,axis=0)
    # print(data)
    # print(data.shape)
    ap = AffinityPropagation(damping=0.9, max_iter=500, convergence_iter=30, preference=p).fit(offline_rss)
    yhat = ap.predict(offline_rss)
    # 检索唯一群集
    clusters = unique(yhat)
    print('clusters.shape',clusters.shape)
    # plt_ap_loc(yhat,clusters,data)
    plt_ap_loc(yhat, clusters, offline_rss, '亲和聚类后的rss值分布')
    plt_ap_loc(yhat, clusters, offline_location, '亲和聚类后的实际位置值分布')

    rw = where(yhat == 1)
    print(rw)
    offline_rss = offline_rss[rw]
    print(offline_rss.shape)
    offline_location = offline_location[rw]

    p = -3000  ##3个中心
    # simi = simi_matrix(offline_rss)
    # p = np.median(simi)
    # p = np.min(9)  ##9个中心，
    # p = np.median(simi)  ##13个中心

    # ap = AffinityPropagation(damping=0.9, max_iter=500, convergence_iter=30, preference=p).fit(offline_rss)
    # cluster_centers_indices = ap.cluster_centers_indices_
    # # 为每个示例分配一个集群
    # yhat = ap.predict(offline_rss)
    # # 检索唯一群集
    # clusters = unique(yhat)
    # plt_ap_loc(yhat,clusters,offline_location)
    # plt_ap_loc(yhat,clusters,offline_rss)


    # rw = where(yhat == 0)
    # offline_rss = offline_rss[rw]
    # offline_location = offline_location[rw]
    # print(offline_rss)
    #
    yhat = ap.predict(rss)
    # 检索唯一群集
    clusters = unique(yhat)
    # plt_ap_loc(yhat,clusters,rss)
    # plt_ap_loc(yhat, clusters, trace)
    print('yhat:',yhat)
    rw = where(yhat == 1)
    trace = trace[rw]
    rss = rss[rw]
    sum_knn_ap = 0
    for i in range(5,21):
        print('第',i,'次')
        sum_knn_ap += knn_reg(offline_rss,offline_location,trace,rss,i)
    print(sum_knn_ap / 16)

    # for i in range(offline_rss.shape[0]):
    #     plt.scatter(i,offline_rss[i][0])
    # plt.show()
